]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
workspace: Fade in instead of zoom to return desktop
authorCarlos Soriano <carlos.soriano89@gmail.com>
Mon, 14 Jul 2014 17:06:08 +0000 (19:06 +0200)
committerCarlos Soriano <carlos.soriano89@gmail.com>
Fri, 8 Aug 2014 14:40:41 +0000 (16:40 +0200)
The zooming animation of the windows looks nice when animating
from the workspace display page, but looks weird from other pages
like apps page or search page since the windows come from nowhere
with an initial position not known to the user.

Instead of that just fade the desktop with the windows in its
original position.

https://bugzilla.gnome.org/show_bug.cgi?id=732901

js/ui/overview.js
js/ui/viewSelector.js
js/ui/workspace.js
js/ui/workspacesView.js

index fc9f05504be239e9bf612c136e6dc9006359480f..50e42e6092cb93b1eda37735ea047c120cab0125 100644 (file)
@@ -623,7 +623,7 @@ const Overview = new Lang.Class({
         this.animationInProgress = true;
         this.visibleTarget = false;
 
-        this.viewSelector.zoomFromOverview();
+        this.viewSelector.animateFromOverview();
 
         // Make other elements fade out.
         Tweener.addTween(this._stack,
index bf2d73311847f84e6dcaddfbc233f690c56ae0a3..80c3035d4903f92e85531583b899718ae19a14c4 100644 (file)
@@ -260,6 +260,16 @@ const ViewSelector = new Lang.Class({
                     this._stageKeyPressId = 0;
                 }
             }));
+        Main.overview.connect('shown', Lang.bind(this,
+            function() {
+                // If we were animating from the desktop view to the
+                // apps page the workspace page was visible, allowing
+                // the windows to animate, but now we no longer want to
+                // show it given that we are now on the apps page or
+                // search page.
+                if (this._activePage != this._workspacesPage)
+                    this._workspacesPage.opacity = 0;
+            }));
 
         Main.wm.addKeybinding('toggle-application-view',
                               new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
@@ -295,29 +305,36 @@ const ViewSelector = new Lang.Class({
     },
 
     _toggleAppsPage: function() {
-        Main.overview.show();
         this._showAppsButton.checked = !this._showAppsButton.checked;
+        Main.overview.show();
     },
 
     showApps: function() {
-        Main.overview.show();
         this._showAppsButton.checked = true;
+        Main.overview.show();
     },
 
     show: function() {
         this.reset();
-
-        this._workspacesDisplay.show();
+        this._workspacesDisplay.show(this._showAppsButton.checked);
         this._activePage = null;
-        this._showPage(this._workspacesPage);
+        if (this._showAppsButton.checked)
+            this._showPage(this._appsPage);
+        else
+            this._showPage(this._workspacesPage);
 
         if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
             Main.overview.fadeOutDesktop();
     },
 
-    zoomFromOverview: function() {
+    animateFromOverview: function() {
+        // Make sure workspace page is fully visible to allow
+        // workspace.js do the animation of the windows
+        this._workspacesPage.opacity = 255;
+
+        this._workspacesDisplay.animateFromOverview(this._activePage != this._workspacesPage);
+
         this._showAppsButton.checked = false;
-        this._workspacesDisplay.zoomFromOverview();
 
         if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
             Main.overview.fadeInDesktop();
@@ -369,6 +386,9 @@ const ViewSelector = new Lang.Class({
     },
 
     _showPage: function(page) {
+        if (!Main.overview.visible)
+            return;
+
         if (page == this._activePage)
             return;
 
index 5fd055b0175c5d4d4f3732045428978ba5177e59..7e157add2c2f2b86e1504752bcc6a059dff622c4 100644 (file)
@@ -34,6 +34,8 @@ const DRAGGING_WINDOW_OPACITY = 100;
 const LAYOUT_SCALE_WEIGHT = 1;
 const LAYOUT_SPACE_WEIGHT = 0.1;
 
+const WINDOW_ANIMATION_MAX_NUMBER_BLENDING = 3;
+
 function _interpolate(start, end, step) {
     return start + (end - start) * step;
 }
@@ -1258,10 +1260,11 @@ const Workspace = new Lang.Class({
             return;
         }
 
-        // We will reposition windows when enter again overview anyway.
+        // We will reposition windows anyway when enter again overview or when ending the windows
+        // animations whith fade animation.
         // In this way we avoid unwanted animations of windows repositioning while
-        // animating overview
-        if (this.leavingOverview)
+        // animating overview.
+        if (this.leavingOverview || this._animatingWindowsFade)
             return;
 
         let initialPositioning = flags & WindowPositionFlags.INITIAL;
@@ -1562,14 +1565,141 @@ const Workspace = new Lang.Class({
         return false;
     },
 
-    // Animate the full-screen to Overview transition.
-    zoomToOverview : function() {
+    fadeToOverview: function() {
+        // We don't want to reposition windows while animating in this way.
+        this._animatingWindowsFade = true;
+        this._overviewShownId = Main.overview.connect('shown', Lang.bind(this,
+                                                                         this._doneShowingOverview));
+        if (this._windows.length == 0)
+            return;
+
+        if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
+            return;
+
+        // Special case maximized windows, since it doesn't make sense
+        // to animate windows below in the stack
+        let topMaximizedWindow;
+        // It is ok to treat the case where there is no maximized
+        // window as if the bottom-most window was maximized given that
+        // it won't affect the result of the animation
+        for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
+            let metaWindow = this._windows[topMaximizedWindow].metaWindow;
+            if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
+                break;
+        }
+
+        let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
+        let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+        let topIndex = this._windows.length - 1;
+        for (let i = 0; i < this._windows.length; i++) {
+            if (i < topMaximizedWindow) {
+                // below top-most maximized window, don't animate
+                let overlay = this._windowOverlays[i];
+                if (overlay)
+                    overlay.hide();
+                this._windows[i].actor.opacity = 0;
+            } else {
+                let fromTop = topIndex - i;
+                let time;
+                if (fromTop < nTimeSlots) // animate top-most windows gradually
+                    time = windowBaseTime * (nTimeSlots - fromTop);
+                else
+                    time = windowBaseTime;
+
+                this._windows[i].actor.opacity = 255;
+                this._fadeWindow(i, time, 0);
+            }
+        }
+    },
+
+    fadeFromOverview: function() {
+        this.leavingOverview = true;
+        this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
+                                                                           this._doneLeavingOverview));
+        if (this._windows.length == 0)
+            return;
+
+        for (let i = 0; i < this._windows.length; i++) {
+            let clone = this._windows[i];
+            Tweener.removeTweens(clone.actor);
+        }
+
+        if (this._repositionWindowsId > 0) {
+            Mainloop.source_remove(this._repositionWindowsId);
+            this._repositionWindowsId = 0;
+        }
+
+        if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
+            return;
+
+        // Special case maximized windows, since it doesn't make sense
+        // to animate windows below in the stack
+        let topMaximizedWindow;
+        // It is ok to treat the case where there is no maximized
+        // window as if the bottom-most window was maximized given that
+        // it won't affect the result of the animation
+        for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
+            let metaWindow = this._windows[topMaximizedWindow].metaWindow;
+            if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
+                break;
+        }
+
+        let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
+        let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+        let topIndex = this._windows.length - 1;
+        for (let i = 0; i < this._windows.length; i++) {
+            if (i < topMaximizedWindow) {
+                // below top-most maximized window, don't animate
+                let overlay = this._windowOverlays[i];
+                if (overlay)
+                    overlay.hide();
+                this._windows[i].actor.opacity = 0;
+            } else {
+                let fromTop = topIndex - i;
+                let time;
+                if (fromTop < nTimeSlots) // animate top-most windows gradually
+                    time = windowBaseTime * (fromTop + 1);
+                else
+                    time = windowBaseTime * nTimeSlots;
+
+                this._windows[i].actor.opacity = 0;
+                this._fadeWindow(i, time, 255);
+            }
+        }
+    },
+
+    _fadeWindow: function(index, time, opacity) {
+        let clone = this._windows[index];
+        let overlay = this._windowOverlays[index];
+
+        if (overlay)
+            overlay.hide();
+
+        if (clone.metaWindow.showing_on_its_workspace()) {
+            let [origX, origY] = clone.getOriginalPosition();
+            clone.actor.scale_x = 1;
+            clone.actor.scale_y = 1;
+            clone.actor.x = origX;
+            clone.actor.y = origY;
+            Tweener.addTween(clone.actor,
+                             { time: time,
+                               opacity: opacity,
+                               transition: 'easeOutQuad'
+                             });
+        } else {
+            // The window is hidden
+            clone.actor.opacity = 0;
+        }
+    },
+
+    zoomToOverview: function() {
         // Position and scale the windows.
         this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
     },
 
-    // Animates the return from Overview mode
-    zoomFromOverview : function() {
+    zoomFromOverview: function() {
         let currentWorkspace = global.screen.get_active_workspace();
 
         this.leavingOverview = true;
@@ -1590,35 +1720,37 @@ const Workspace = new Lang.Class({
             return;
 
         // Position and scale the windows.
-        for (let i = 0; i < this._windows.length; i++) {
-            let clone = this._windows[i];
-            let overlay = this._windowOverlays[i];
-
-            if (overlay)
-                overlay.hide();
+        for (let i = 0; i < this._windows.length; i++)
+           this._zoomWindowFromOverview(i);
+    },
 
-            if (clone.metaWindow.showing_on_its_workspace()) {
-                let [origX, origY] = clone.getOriginalPosition();
-
-                Tweener.addTween(clone.actor,
-                                 { x: origX,
-                                   y: origY,
-                                   scale_x: 1.0,
-                                   scale_y: 1.0,
-                                   time: Overview.ANIMATION_TIME,
-                                   opacity: 255,
-                                   transition: 'easeOutQuad'
-                                 });
-            } else {
-                // The window is hidden, make it shrink and fade it out
-                Tweener.addTween(clone.actor,
-                                 { scale_x: 0,
-                                   scale_y: 0,
-                                   opacity: 0,
-                                   time: Overview.ANIMATION_TIME,
-                                   transition: 'easeOutQuad'
-                                 });
-            }
+    _zoomWindowFromOverview: function(index) {
+        let clone = this._windows[index];
+        let overlay = this._windowOverlays[index];
+
+        if (overlay)
+            overlay.hide();
+
+        if (clone.metaWindow.showing_on_its_workspace()) {
+            let [origX, origY] = clone.getOriginalPosition();
+            Tweener.addTween(clone.actor,
+                             { x: origX,
+                               y: origY,
+                               scale_x: 1.0,
+                               scale_y: 1.0,
+                               time: Overview.ANIMATION_TIME,
+                               opacity: 255,
+                               transition: 'easeOutQuad'
+                             });
+        } else {
+            // The window is hidden, make it shrink and fade it out
+            Tweener.addTween(clone.actor,
+                             { scale_x: 0,
+                               scale_y: 0,
+                               opacity: 0,
+                               time: Overview.ANIMATION_TIME,
+                               transition: 'easeOutQuad'
+                             });
         }
     },
 
@@ -1657,6 +1789,11 @@ const Workspace = new Lang.Class({
         this.leavingOverview = false;
     },
 
+    _doneShowingOverview: function() {
+        this._animatingWindowsFade = false;
+        this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
+    },
+
     // Tests if @actor belongs to this workspaces and monitor
     _isMyWindow : function (actor) {
         let win = actor.meta_window;
index 61df6ab9630373caad583acd1377256aea8a46a1..004ac81ae079e9715e28b50b400680f1923005a5 100644 (file)
@@ -21,6 +21,11 @@ const WORKSPACE_SWITCH_TIME = 0.25;
 // Note that mutter has a compile-time limit of 36
 const MAX_WORKSPACES = 16;
 
+const AnimationType = {
+    ZOOM: 0,
+    FADE: 1
+};
+
 const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
 
 const WorkspacesViewBase = new Lang.Class({
@@ -142,17 +147,25 @@ const WorkspacesView = new Lang.Class({
         return this._workspaces[active];
     },
 
-    zoomToOverview: function() {
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].zoomToOverview();
+    animateToOverview: function(animationType) {
+        for (let w = 0; w < this._workspaces.length; w++) {
+            if (animationType == AnimationType.ZOOM)
+                this._workspaces[w].zoomToOverview();
+            else
+                this._workspaces[w].fadeToOverview();
+        }
         this._updateWorkspaceActors(false);
     },
 
-    zoomFromOverview: function() {
+    animateFromOverview: function(animationType) {
         this.actor.remove_clip();
 
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].zoomFromOverview();
+        for (let w = 0; w < this._workspaces.length; w++) {
+            if (animationType == AnimationType.ZOOM)
+                this._workspaces[w].zoomFromOverview();
+            else
+                this._workspaces[w].fadeFromOverview();
+        }
     },
 
     syncStacking: function(stackIndices) {
@@ -365,12 +378,18 @@ const ExtraWorkspaceView = new Lang.Class({
         this._workspace.setActualGeometry(this._actualGeometry);
     },
 
-    zoomToOverview: function() {
-        this._workspace.zoomToOverview();
+    animateToOverview: function(animationType) {
+        if (animationType == AnimationType.ZOOM)
+            this._workspace.zoomToOverview();
+        else
+            this._workspace.fadeToOverview();
     },
 
-    zoomFromOverview: function() {
-        this._workspace.zoomFromOverview();
+    animateFromOverview: function(animationType) {
+        if (animationType == AnimationType.ZOOM)
+            this._workspace.zoomFromOverview();
+        else
+            this._workspace.fadeFromOverview();
     },
 
     syncStacking: function(stackIndices) {
@@ -462,10 +481,16 @@ const WorkspacesDisplay = new Lang.Class({
         return this._getPrimaryView().actor.navigate_focus(from, direction, false);
     },
 
-    show: function() {
+    show: function(fadeOnPrimary) {
         this._updateWorkspacesViews();
-        for (let i = 0; i < this._workspacesViews.length; i++)
-            this._workspacesViews[i].zoomToOverview();
+        for (let i = 0; i < this._workspacesViews.length; i++) {
+            let animationType;
+            if (fadeOnPrimary && i == this._primaryIndex)
+                animationType = AnimationType.FADE;
+            else
+                animationType = AnimationType.ZOOM;
+            this._workspacesViews[i].animateToOverview(animationType);
+        }
 
         this._restackedNotifyId =
             Main.overview.connect('windows-restacked',
@@ -474,9 +499,15 @@ const WorkspacesDisplay = new Lang.Class({
             this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
     },
 
-    zoomFromOverview: function() {
-        for (let i = 0; i < this._workspacesViews.length; i++)
-            this._workspacesViews[i].zoomFromOverview();
+    animateFromOverview: function(fadeOnPrimary) {
+        for (let i = 0; i < this._workspacesViews.length; i++) {
+            let animationType;
+            if (fadeOnPrimary && i == this._primaryIndex)
+                animationType = AnimationType.FADE;
+            else
+                animationType = AnimationType.ZOOM;
+            this._workspacesViews[i].animateFromOverview(animationType);
+        }
     },
 
     hide: function() {